"""
JWT 工具 & 密码哈希工具

提供：
- 密码哈希与校验
- JWT 编码与解码
- 当前用户获取（同步）
"""
from datetime import datetime, timedelta
from typing import Optional

from jose import JWTError, jwt
from passlib.context import CryptContext

from common.config import settings
from common.exceptions import BizException, ErrorCode
from common.logger import create_logger

# 使用 bcrypt 进行密码哈希
pwd_ctx = CryptContext(schemes=["bcrypt"], deprecated="auto")

logger = create_logger(__name__)


def verify_password(plain: str, hashed: str) -> bool:
	"""
	校验明文密码与哈希密码是否一致

	Args:
		plain: 明文密码
		hashed: 哈希密码

	Returns:
		bool: 校验结果
	"""
	return pwd_ctx.verify(plain, hashed)


def hash_password(plain: str) -> str:
	"""
	对明文密码进行哈希加密

	Args:
		plain: 明文密码

	Returns:
		str: 哈希后的密码
	"""
	return pwd_ctx.hash(plain)


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
	"""
	生成 JWT 访问令牌

	Args:
		data: 要编码的数据字典
		expires_delta: 自定义过期时间，默认使用配置

	Returns:
		str: JWT 令牌
	"""
	if not isinstance(data, dict):
		raise ValueError("data 必须是字典类型")

	to_encode = data.copy()
	expire = datetime.now() + (expires_delta or timedelta(minutes=settings.access_token_expire_minutes))
	to_encode.update({"exp": expire})

	return jwt.encode(to_encode, settings.jwt_secret_key, algorithm=settings.jwt_algorithm)


def decode_token(token: str) -> str:
	"""
	解码 JWT 令牌并提取用户名（sub）

	Args:
		token: JWT 令牌

	Returns:
		str: 用户名

	Raises:
		BizException: 令牌无效或缺失字段
	"""
	if not token or not isinstance(token, str):
		raise BizException.from_error_code(ErrorCode.INVALID_CREDENTIALS, message="令牌格式错误")

	try:
		payload = jwt.decode(token, settings.jwt_secret_key, algorithms=[settings.jwt_algorithm])
		username: str = payload.get("sub")
		if username is None:
			raise ValueError("JWT 缺少 sub 字段")
		return username
	except (JWTError, ValueError) as e:
		logger.error("JWT decode fail: %s | token=%s", str(e), token)
		raise BizException.from_error_code(
			ErrorCode.INVALID_CREDENTIALS,
			message="令牌验证失败",
			headers={"WWW-Authenticate": "Bearer"}
		) from e
